import { IPool } from "../common/Common";
import { getPoolUID } from "./PoolSign";

interface PoolItemConstructor<T> {
    new(): T;
}

export default class Pool<T> {

    static poolMap: { [guid: number]: Pool<IPool> } = {};

    public guid: number;
    private clazz: PoolItemConstructor<T>;
    private items: T[] = [];
    private maxSize: number;

    private constructor(creator: PoolItemConstructor<T>) {
        this.clazz = creator as any;
    }

    static create<T>(creator: PoolItemConstructor<T>) {
        return new Pool(creator);
    }

    static getGuid(tar: any) {
        let descrip = Reflect.getOwnPropertyDescriptor(tar, "$_POOL");
        if (descrip) {
            return descrip.value;
        }

        let value = getPoolUID();
        Reflect.defineProperty(tar, "$_POOL", { value: value, configurable: false, writable: false, enumerable: false });
        return value;
    }

    static getPoolByCreator<T>(creator: PoolItemConstructor<T>, maxSize: number = 10) {
        let guid = this.getGuid(creator);
        let pool = this.poolMap[guid];
        if (!pool) {
            this.poolMap[guid] = pool = new Pool(creator);
            pool.guid = guid;
            pool.maxSize = maxSize;
        }
        return pool;
    }

    static put(tar: any) {
        let creator = Reflect.getPrototypeOf(tar).constructor;
        this.getPoolByCreator(<any>creator).put(tar);
    }

    static get<T>(creator: PoolItemConstructor<T>) {
        return this.getPoolByCreator<T>(creator).get() as T;
    }

    static dispose<T>(creator: PoolItemConstructor<T>) {
        let pool = this.getPoolByCreator(creator);
        if (pool) {
            let guid = pool.guid;
            pool.dispose();
            delete this.poolMap[guid];
        }
    }

    /**
     * 对象池只会清理对象引用，回收前需要玩家手动清理当前对象不需要的引用
     */
    put(item: T) {
        if (!this.maxSize || this.items.length <= this.maxSize) {
            this.items.push(item);
        }
    }

    get(): T {
        let item = this.items.shift() || new this.clazz();

        //暂时保留
        if (item["destroyed"]) {
            console.error("Pool.get destroyed")
            return new this.clazz();
        }
        return item;
    }


    dispose() {
        this.guid = 0;
        for (let i = 0; i < this.items.length; i++) {
            let item = this.items[i];
            if (item["removeSelf"]) {
                item["removeSelf"]();
            }
            if (item["destroy"]) {
                item["destroy"]();
            }
        }
        this.items.length = 0;
    }
}
